package cn.jetbrain.netbeans.pdfviewer.view;

import cn.jetbrain.netbeans.pdfviewer.PDFViewer;
import com.sun.pdfview.PDFFile;
import com.sun.pdfview.PDFPage;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.Stroke;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;

import javax.swing.JPanel;
import javax.swing.JViewport;
import javax.swing.Scrollable;
import javax.swing.SwingUtilities;

public class ThumbPanel extends JPanel implements Runnable, Scrollable {

    PDFFile file;
    Image images[];
    int lineheight = 100;
    int defaultWidth = 100;

    int xloc[];

    Thread anim;
    int showing = -1;
    int needdrawn = -1;
    boolean defaultNotSet = true;
    PageChangeListener listener;

    public ThumbPanel(PDFFile file) {
        super();
        this.file = file;
        if (file != null) {
            int count = file.getNumPages();
            images = new Image[count];
            xloc = new int[count];
            setPreferredSize(new Dimension(defaultWidth, 200));
            addMouseListener(new MouseAdapter() {
                @Override
                public void mouseClicked(MouseEvent evt) {
                    handleClick(evt.getX(), evt.getY());
                }
            });
            anim = new Thread(this);
            anim.start();
        } else {
            images = new Image[0];
            setPreferredSize(new Dimension(defaultWidth, 200));
        }
        setFocusable(true);
    }

    public void run() {
        int workingon = 0;
        while (anim == Thread.currentThread()) {
            if (needdrawn >= 0) {
                workingon = needdrawn;
                needdrawn = -1;
            }
            // find an unfinished page
            int loop;
            for (loop = images.length; loop > 0; loop--) {
                if (images[workingon] == null) {
                    break;
                }
                workingon++;
                if (workingon >= images.length) {
                    workingon = 0;
                }
            }
            if (loop == 0) {
                // done all pages.
                break;
            }
            // build the page
            try {
                int pagetoread = workingon + 1;
                PDFPage p = file.getPage(pagetoread, true);
                Dimension pageSize = p.getUnstretchedSize(76, 76, null);
                int pagetowrite = workingon;

                Image i = p.getImage(pageSize.width, pageSize.height, null, this, true, true);
                images[pagetowrite] = i;

                if (defaultNotSet) {
                    defaultNotSet = false;
                }
                repaint();
            } catch (Exception e) {
                e.printStackTrace();

                images[workingon] = new BufferedImage(76, 76, BufferedImage.TYPE_BYTE_BINARY);
            }
        }
    }

    public void addPageChangeListener(PageChangeListener pl) {
        listener = pl;
    }

    public void removePageChangeListener(PageChangeListener pl) {
        listener = null;
    }

    public void stop() {
        anim = null;
    }

    public void setDefaultWidth(int width) {
        defaultWidth = width;
    }

    public void handleClick(int x, int y) {
        int linecount = -1;
        int line = y / lineheight;
        for (int i = 0; i < xloc.length; i++) {
            if (xloc[i] == 0) {
                linecount++;
            }
            if (line == linecount && xloc[i] + defaultWidth > x) {
                showPage(i);
                break;
            }
        }
    }

    public void pageShown(int pagenum) {
        if (showing != pagenum) {
            if (pagenum >= 0 && getParent() instanceof JViewport) {
                int y = -lineheight;
                for (int i = 0; i <= pagenum; i++) {
                    if (xloc[i] == 0) {
                        y += lineheight;
                    }
                }
                Rectangle r = new Rectangle(xloc[pagenum], y,defaultWidth,lineheight);
                scrollRectToVisible(r);
            }
            showing = pagenum;
            repaint();
        }
    }

    public void showPage(int pagenum) {
        pageShown(pagenum);
        SwingUtilities.invokeLater(new GotoLater(pagenum));
    }

    class GotoLater implements Runnable {

        int page;

        public GotoLater(int pagenum) {
            page = pagenum;
        }

        public void run() {
            if (listener != null) {
                listener.gotoPage(page);
            }
        }
    }

    @Override
    public void paint(Graphics g) {
        int x = 0;
        int y = 0;
        int maxwidth = 0;
        Rectangle clip = g.getClipBounds();
        g.setColor(PDFViewer.THUMBS_BACKGROUND);
        int width = getWidth();
        g.fillRect(0, 0, width, getHeight());

        for (int i = 0; i < images.length; i++) {
            // calculate the x location of the thumbnail, based on its width
            int w = defaultWidth;
            int imgw = 59;
            int imgh = 76;
            if (images[i] != null) {
                imgw = images[i].getWidth(null);
                imgh = images[i].getHeight(null);
            }
            // need a new line?
            if (x + w > width && x != 0) {
                x = 0;
                y += lineheight;
            }
            // if the thumbnail is visible, draw it.
            if (clip.intersects(new Rectangle(x, y, w, lineheight))) {
                if (i == showing) {
                    g.setColor(new Color(0x99C1DA));
                    g.fillRect(x, y, w, lineheight);
                    g.setColor(new Color(0x663E25));
                    Stroke oldStroke=((Graphics2D)g).getStroke();
                    ((Graphics2D)g).setStroke(new BasicStroke(1.0f,BasicStroke.CAP_BUTT,BasicStroke.JOIN_BEVEL, 1.0f,new float[] { 1.0f, 1.0f, 1.0f, 1.0f },0.0f));
                    g.drawRect(x, y, w, lineheight);
                    ((Graphics2D)g).setStroke(oldStroke);
                }

                g.setColor(new Color(0xD6D6D6));
                g.fillRect(x + 23, y + 6, imgw, imgh);
                g.setColor(new Color(0x7B7B7B));
                g.fillRect(x + 22, y + 5, imgw, imgh);

                if (images[i] != null) {
                    // thumbnail is ready.
                    g.drawImage(images[i], x + 20, y + 3, this);
                } else {
                    // thumbnail isn't ready.  Remember that we need it...
                    if (needdrawn == -1) {
                        needdrawn = i;
                    }
                    // ... and draw a blank thumbnail.
                    g.setColor(Color.WHITE);
                    g.fillRect(x + 20, y + 3, imgw,imgh);
                }
                g.setColor(new Color(0xA3A3A3));
                g.drawRect(x + 20, y + 3, imgw,imgh);
                // draw the selection highlight if needed.
                if (i == showing) {
                    g.setColor(Color.red);
                    g.drawRect(x + 20, y + 3, imgw,imgh);
                    g.drawRect(x + 19, y + 2, imgw + 2, imgh + 2);
                }

                g.setColor(Color.BLACK);
                g.drawString((i+1)+"", x+45, y+92);
            }
            // save the x location of this thumbnail.
            xloc[i] = x;
            x += w;
            // remember the longest line
            if (x > maxwidth) {
                maxwidth = x;
            }
        }
        // if there weren't any thumbnails, make a default line width
        if (maxwidth == 0) {
            maxwidth = defaultWidth;
        }
        Dimension d = getPreferredSize();
        if (d.height != y + lineheight || d.width != maxwidth) {
            setPreferredSize(new Dimension(maxwidth, y + lineheight));
            revalidate();
        }
    }

    public Dimension getPreferredScrollableViewportSize() {
        return getPreferredSize();
    }

    public int getScrollableBlockIncrement(Rectangle visrect, int orientation,
            int direction) {
        return Math.max(lineheight, (visrect.height / lineheight) * lineheight);
    }

    public boolean getScrollableTracksViewportHeight() {
        return false;
    }

    public boolean getScrollableTracksViewportWidth() {
        return true;
    }

    public int getScrollableUnitIncrement(Rectangle visrect, int orientation,
            int direction) {
        return lineheight;
    }
}
